package com.powernode.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.powernode.constant.BusinessEnum;
import com.powernode.constant.HttpConstants;
import com.powernode.constant.ResourceConstants;
import com.powernode.filter.TokenTranslationFilter;
import com.powernode.model.Result;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import java.io.PrintWriter;

/**
 * @create: 2024/7/16
 * @author: gyhe10
 * @description: spring-security安全框架的资源服务器配置类
 **/

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)// 开启方法权限注解
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private TokenTranslationFilter tokenTranslationFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置资源服务器的权限控制规则
        // 关闭跨站请求伪造防护
        http.csrf().disable();
        // 关闭跨域访问控制
        http.cors().disable();
        // 关闭Session策略
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 编写token过滤器，将token转换为SpringSecurity安全框架认证的用户信息，并将用户信息放入当前资源服务器的上下文中
        http.addFilterBefore(tokenTranslationFilter, UsernamePasswordAuthenticationFilter.class);

        // 配置处理携带token但权限不足的请求
        http.exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint())// 处理没有携带token的请求
                .accessDeniedHandler(accessDeniedHandler());// 处理携带token，但是权限不足的请求

        // 配置其他请求
        http.authorizeHttpRequests()
                .antMatchers(ResourceConstants.RESOURCE_ALLOW_URLS)
                .permitAll()
                .anyRequest()
                .authenticated();// 除需要放行的请求，其他所有请求都需要认证
    }

    /**
     * 处理没有携带token的请求
     * @return
     */
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> {
            // 设置响应头信息
            response.setContentType(HttpConstants.APPLICATION_JSON);
            response.setCharacterEncoding(HttpConstants.UTF_8);

            // 创建项目统一响应结果
            Result<Object> result = Result.fail(BusinessEnum.UNAUTHORIZED);

            // 将响应结果转为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String s = objectMapper.writeValueAsString(result);

            // 返回响应结果
            PrintWriter writer = response.getWriter();
            writer.write(s);
            writer.flush();
            writer.close();
        };
    }

    /**
     * 处理携带token，但是权限不足的请求
     * @return
     */
    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            // 设置响应头信息
            response.setContentType(HttpConstants.APPLICATION_JSON);
            response.setCharacterEncoding(HttpConstants.UTF_8);

            // 创建项目统一响应结果
            Result<Object> result = Result.fail(BusinessEnum.ACCESS_DENIED_FAIL);

            // 将响应结果转为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String s = objectMapper.writeValueAsString(result);

            // 返回响应结果
            PrintWriter writer = response.getWriter();
            writer.write(s);
            writer.flush();
            writer.close();
        };
    }
}
